package com.yun.jing.common.config.security;




import com.yun.jing.common.config.jwt.JwtAccessDeniedHandler;
import com.yun.jing.common.config.jwt.JwtAuthenticationEntryPoint;
import com.yun.jing.common.config.jwt.JwtTokenUtils;
import com.yun.jing.common.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Spring Security配置类
 *（token授权认证配置）
 */

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private AuthenticationSuccessHandler authenticationSuccessHandler;

    //jwt拦截器
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationFilter;


//    @Autowired
//    private LoginFailureHandler1 loginFailureHandler;

//    //权限拦截器
//    @Autowired
//    private CustomPermissionEvaluator customPermissionEvaluator;

    /**
     * 指定加密方式
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
    private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    private final JwtTokenUtils jwtTokenUtils;

    public WebSecurityConfig(JwtAccessDeniedHandler jwtAccessDeniedHandler, JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, JwtTokenUtils jwtTokenUtils) {

        this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
        this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
        this.jwtTokenUtils = jwtTokenUtils;

    }

    /**
     * 安全核心配置器
     * @param
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                // 禁用 CSRF
                .csrf().requireCsrfProtectionMatcher(new CsrfSecurityRequestMatcher())//关闭cors,这行必须要有
               .and().cors().disable()
                // 授权异常
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)

                // 防止iframe 造成跨域
                .and()
                .headers()
                .frameOptions()
                .disable()

                // 不创建会话
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .authorizeRequests()

                // 放行静态资源
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/webSocket/**"
                ).permitAll()

                // 放行swagger
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/*/api-docs").permitAll()

                // 放行文件访问
                .antMatchers("/file/**").permitAll()

                // 放行druid
                .antMatchers("/druid/**").permitAll()

                // 放行OPTIONS请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                //允许匿名及登录用户访问
                .antMatchers("/server/login", "/server/captcha","/server/img/save").permitAll()

                // 所有请求都需要认证
                .anyRequest().authenticated();

                //指定登录页的路径
//                .and().formLogin()  .usernameParameter("username")
//                .passwordParameter("password").loginPage("/server/login").loginProcessingUrl("/server/login")
//                .successHandler(authenticationSuccessHandler).failureHandler(loginFailureHandler) ;
        // 禁用缓存
        httpSecurity.headers().cacheControl();

        // 添加JWT filter(用于进行验证)
        httpSecurity
                .apply(new TokenConfigurer(jwtTokenUtils));
        //配置permission
//        httpSecurity.authorizeRequests().expressionHandler(webSecurityExpressionHandler1());
    }


    /**
     * token拦截配置器
     */
    public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

        private final JwtTokenUtils jwtTokenUtils;

        public TokenConfigurer(JwtTokenUtils jwtTokenUtils){

            this.jwtTokenUtils = jwtTokenUtils;
        }

        @Override
        public void configure(HttpSecurity http) {
            //设置过滤器使用的jwt工具
            JwtAuthenticationTokenFilter customFilter = new JwtAuthenticationTokenFilter(jwtTokenUtils);
            //添加拦截(拦截登录的请求)
//            http.addFilterBefore(jwtAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);
            http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }

//    /**
//     * 登录认证方式
//     */
//    @Autowired
//    private UserServiceOne userService;



//    /**
//     * 身份验证配置器
//     * @param
//     * @throws Exception
//     */
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        //身份验证方法指定
//        auth.userDetailsService(userService);
//    }


    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler(JwtTokenUtils jwtTokenUtils)
    {

       // return  responseResult.setData(jwtTokenUtils.createToken(map));
        return (request, response, authentication) ->
        {
            if (response.isCommitted())
            {
                return;
            }
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            User principal = (User) authentication.getPrincipal();
            String username = principal.getUsername();
            String password = principal.getPassword();
            Map map = new HashMap();
            map.put("username",username);
            map.put("password",userDetails.getAuthorities());
            map.put("role",userDetails.getAuthorities());
            System.out.println(userDetails.getAuthorities());
//            ResponseResult responseResult = new ResponseResult();
//            responseResult.setCreateSuccess(jwtTokenUtils.createToken(map));
//            responseResult.setData(jwtTokenUtils.createToken(map));
          //  response.setHeader("Access-Control-Expose-Headers",jwtTokenUtils.createToken(map));
            response.setHeader("token",jwtTokenUtils.createToken(map));
            response.setContentType("application/json");
            response.getOutputStream().write("登录成功".getBytes("UTF-8"));
        };
    }
//
//    /**
//     * 自定义注入权限PermissionEvaluator
//     */
//    @Bean
//    public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler1(){
//        DefaultWebSecurityExpressionHandler handler=new DefaultWebSecurityExpressionHandler();
//        handler.setPermissionEvaluator(customPermissionEvaluator);
//        return handler;
//    }

    /**
     * security的跨域问题
     * @return
     */
    @Bean
   public CorsConfigurationSource corsConfigurationSource() {
          CorsConfiguration corsConfiguration = new CorsConfiguration();
          //放行那些域
        corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8087","http://localhost:8080"));
          //放行那些请求
        corsConfiguration.setAllowedMethods(Arrays.asList("GET","POST","PUT","OPTIONS"));
        //是否发送cookies
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        //放行那些头
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        //暴露那些头部信息
        corsConfiguration.addExposedHeader("access-control-Expose-Headers");
        corsConfiguration.addExposedHeader("token");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        //去掉";"黑名单
        firewall.setAllowSemicolon(true);
        //加入自定义的防火墙
        web.httpFirewall(firewall);
        super.configure(web);
    }

}

